package com.yuno.mock.controller;

import com.yuno.mock.dto.ExcelReadRequest;
import com.yuno.mock.dto.ExcelReadResult;
import com.yuno.mock.service.ExcelReaderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * Excel读取控制器
 * 提供Excel文件读取的REST API接口
 * 
 * @author yuno
 * @since 2024-01-01
 */
@Slf4j
@RestController
@RequestMapping("/api/excel")
public class ExcelReaderController {

    @Autowired
    private ExcelReaderService excelReaderService;

    /**
     * 文件上传接口
     * 
     * @param file 上传的Excel文件
     * @return 上传结果和文件路径
     */
    @PostMapping(value = "/upload", consumes = "multipart/form-data")
    public ResponseEntity<Map<String, Object>> uploadFile(@RequestParam("file") MultipartFile file) {
        log.info("开始处理文件上传请求");
        
        try {
            // 检查文件是否为空
            if (file.isEmpty()) {
                log.warn("文件上传失败: 文件为空");
                return ResponseEntity.badRequest().body(Map.of(
                    "success", false,
                    "message", "文件不能为空"
                ));
            }

            // 验证文件类型
            String originalFilename = file.getOriginalFilename();
            log.debug("上传文件名: {}, 文件大小: {} bytes", originalFilename, file.getSize());
            
            if (originalFilename == null || (!originalFilename.endsWith(".xlsx") && !originalFilename.endsWith(".xls"))) {
                log.warn("文件上传失败: 不支持的文件格式 - {}", originalFilename);
                return ResponseEntity.badRequest().body(Map.of(
                    "success", false,
                    "message", "只支持Excel文件格式(.xlsx, .xls)"
                ));
            }

            // 创建上传目录
            String uploadDir = "uploads";
            Path uploadPath = Paths.get(uploadDir);
            if (!Files.exists(uploadPath)) {
                log.info("创建上传目录: {}", uploadPath.toAbsolutePath());
                Files.createDirectories(uploadPath);
            }

            // 生成唯一文件名
            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            String uniqueFilename = UUID.randomUUID().toString() + fileExtension;
            Path filePath = uploadPath.resolve(uniqueFilename);
            
            log.debug("生成唯一文件名: {} -> {}", originalFilename, uniqueFilename);

            // 保存文件
            long startTime = System.currentTimeMillis();
            Files.copy(file.getInputStream(), filePath);
            long endTime = System.currentTimeMillis();

            log.info("文件上传成功: {} -> {}, 耗时: {}ms, 文件大小: {} bytes", 
                    originalFilename, filePath.toString(), (endTime - startTime), file.getSize());

            return ResponseEntity.ok(Map.of(
                "success", true,
                "message", "文件上传成功",
                "filePath", filePath.toString(),
                "originalName", originalFilename,
                "size", file.getSize()
            ));

        } catch (IOException e) {
            log.error("文件上传失败: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().body(Map.of(
                "success", false,
                "message", "文件上传失败: " + e.getMessage()
            ));
        } catch (Exception e) {
            log.error("文件上传过程中发生未知错误: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().body(Map.of(
                "success", false,
                "message", "文件上传失败: " + e.getMessage()
            ));
        }
    }

    /**
     * 同步读取Excel文件
     * 
     * @param request Excel读取请求
     * @return Excel读取结果
     */
    @PostMapping("/read/sync")
    public ResponseEntity<ExcelReadResult> readExcelSync(@RequestBody ExcelReadRequest request) {
        log.info("开始同步读取Excel文件: {}, 请求ID: {}", request.getFilePath(), request.getRequestId());
        log.debug("同步读取请求参数: sheetIndex={}, startRow={}, endRow={}, includeHeader={}", 
                request.getSheetIndex(), request.getStartRow(), request.getEndRow(), request.getIncludeHeader());
        
        long startTime = System.currentTimeMillis();
        try {
            ExcelReadResult result = excelReaderService.readExcelSync(request);
            long endTime = System.currentTimeMillis();
            
            log.info("同步读取Excel文件完成: {}, 状态: {}, 耗时: {}ms, 读取行数: {}", 
                    request.getFilePath(), result.getStatus(), (endTime - startTime), result.getTotalRows());
            
            if (result.getData() != null) {
                log.debug("返回数据行数: {}", result.getData().size());
            }
            
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("同步读取Excel文件失败: {}, 请求ID: {}, 耗时: {}ms, 错误: {}", 
                    request.getFilePath(), request.getRequestId(), (endTime - startTime), e.getMessage(), e);
            
            ExcelReadResult errorResult = new ExcelReadResult();
            errorResult.setRequestId(request.getRequestId());
            errorResult.setStatus("ERROR");
            errorResult.setMessage("读取失败: " + e.getMessage());
            return ResponseEntity.ok(errorResult);
        }
    }

    /**
     * 异步读取Excel文件
     * 
     * @param request Excel读取请求
     * @return 异步任务响应
     */
    @PostMapping("/read/async")
    public ResponseEntity<Map<String, Object>> readExcelAsync(@RequestBody ExcelReadRequest request) {
        log.info("开始异步读取Excel文件: {}, 请求ID: {}", request.getFilePath(), request.getRequestId());
        log.debug("异步读取请求参数: sheetIndex={}, startRow={}, endRow={}, includeHeader={}", 
                request.getSheetIndex(), request.getStartRow(), request.getEndRow(), request.getIncludeHeader());
        
        try {
            CompletableFuture<ExcelReadResult> futureResult = excelReaderService.readExcelAsync(request);
            
            Map<String, Object> response = new HashMap<>();
            response.put("requestId", request.getRequestId());
            response.put("status", "SUBMITTED");
            response.put("message", "异步任务已提交");
            response.put("taskId", request.getRequestId());
            
            log.info("异步读取Excel任务已提交: {}, 请求ID: {}, 任务ID: {}", 
                    request.getFilePath(), request.getRequestId(), request.getRequestId());
            log.debug("异步任务响应: status={}, message={}", response.get("status"), response.get("message"));
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("异步读取Excel文件失败: {}, 请求ID: {}, 错误: {}", 
                    request.getFilePath(), request.getRequestId(), e.getMessage(), e);
            
            Map<String, Object> errorResponse = Map.of(
                "requestId", request.getRequestId(),
                "status", "ERROR",
                "message", "异步任务提交失败: " + e.getMessage()
            );
            return ResponseEntity.ok(errorResponse);
        }
    }

    /**
     * 分片读取Excel文件
     * 
     * @param request Excel读取请求
     * @return 分片读取结果
     */
    @PostMapping("/read/sharding")
    public ResponseEntity<ExcelReadResult> readExcelWithSharding(@RequestBody ExcelReadRequest request) {
        log.info("开始分片读取Excel文件: {}, 请求ID: {}", request.getFilePath(), request.getRequestId());
        log.debug("分片读取请求参数: sheetIndex={}, startRow={}, endRow={}, includeHeader={}, maxRowsPerShard={}", 
                request.getSheetIndex(), request.getStartRow(), request.getEndRow(), request.getIncludeHeader(), request.getMaxRowsPerShard());
        
        long startTime = System.currentTimeMillis();
        try {
            List<String> taskIds = excelReaderService.readExcelWithSharding(request);
            long endTime = System.currentTimeMillis();
            
            // 创建响应结果
            ExcelReadResult result = new ExcelReadResult();
            result.setStatus("SUBMITTED");
            result.setMessage("分片任务已提交，任务数量: " + taskIds.size());
            result.setRequestId(request.getRequestId());
            result.setTotalRows(0L); // 分片任务提交时还不知道总行数
            
            Map<String, Object> metadata = new HashMap<>();
            metadata.put("taskIds", taskIds);
            metadata.put("shardCount", taskIds.size());
            result.setMetadata(metadata);
            
            log.info("分片读取Excel任务已提交: {}, 状态: {}, 耗时: {}ms, 分片数: {}", 
                    request.getFilePath(), result.getStatus(), (endTime - startTime), taskIds.size());
            
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("分片读取Excel文件失败: {}, 请求ID: {}, 耗时: {}ms, 错误: {}", 
                    request.getFilePath(), request.getRequestId(), (endTime - startTime), e.getMessage(), e);
            
            ExcelReadResult errorResult = new ExcelReadResult();
            errorResult.setRequestId(request.getRequestId());
            errorResult.setStatus("ERROR");
            errorResult.setMessage("分片读取失败: " + e.getMessage());
            return ResponseEntity.ok(errorResult);
        }
    }

    /**
     * 获取Excel文件信息
     * 
     * @param filePath Excel文件路径
     * @return Excel文件信息
     */
    @GetMapping("/info")
    public ResponseEntity<Map<String, Object>> getExcelInfo(@RequestParam String filePath) {
        log.info("开始获取Excel文件信息: {}", filePath);
        
        long startTime = System.currentTimeMillis();
        try {
            ExcelReadRequest request = new ExcelReadRequest();
            request.setFilePath(filePath);
            
            Map<String, Object> info = excelReaderService.getExcelInfo(request);
            long endTime = System.currentTimeMillis();
            
            Map<String, Object> result = new HashMap<>();
            result.put("filePath", filePath);
            result.put("info", info);
            result.put("processingTime", (endTime - startTime));
            
            log.info("Excel文件信息获取完成: {}, 耗时: {}ms", 
                    filePath, (endTime - startTime));
            
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("获取Excel文件信息失败: {}, 耗时: {}ms, 错误: {}", 
                    filePath, (endTime - startTime), e.getMessage(), e);
            
            Map<String, Object> errorResult = Map.of(
                "filePath", filePath,
                "status", "ERROR",
                "message", "获取文件信息失败: " + e.getMessage()
            );
            return ResponseEntity.ok(errorResult);
        }
    }

    /**
     * 获取Excel文件的所有Sheet页信息
     * 
     * @param filePath Excel文件路径
     * @return Sheet页信息列表
     */
    @GetMapping("/sheets")
    public ResponseEntity<Map<String, Object>> getExcelSheets(@RequestParam String filePath) {
        log.info("开始获取Excel文件的Sheet页信息: {}", filePath);
        
        long startTime = System.currentTimeMillis();
        try {
            List<Map<String, Object>> sheets = excelReaderService.getExcelSheets(filePath);
            long endTime = System.currentTimeMillis();
            
            Map<String, Object> result = new HashMap<>();
            result.put("filePath", filePath);
            result.put("sheetCount", sheets.size());
            result.put("sheets", sheets);
            result.put("status", "SUCCESS");
            result.put("message", "Sheet页信息获取成功");
            
            log.info("Excel文件Sheet页信息获取完成: {}, 耗时: {}ms, Sheet数量: {}", 
                    filePath, (endTime - startTime), sheets.size());
            
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("获取Excel文件Sheet页信息失败: {}, 耗时: {}ms, 错误: {}", 
                    filePath, (endTime - startTime), e.getMessage(), e);
            
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("filePath", filePath);
            errorResult.put("status", "ERROR");
            errorResult.put("message", "获取Sheet页信息失败: " + e.getMessage());
            errorResult.put("sheetCount", 0);
            errorResult.put("sheets", new ArrayList<>());
            
            return ResponseEntity.ok(errorResult);
        }
    }

    /**
     * 获取任务进度
     * 
     * @param requestId 请求ID
     * @return 任务进度信息
     */
    @GetMapping("/progress/{requestId}")
    public ResponseEntity<Map<String, Object>> getProgress(@PathVariable String requestId) {
        log.debug("查询任务进度: {}", requestId);
        
        try {
            Double progress = excelReaderService.getProgress(requestId);
            
            Map<String, Object> result = new HashMap<>();
            result.put("requestId", requestId);
            result.put("progress", progress);
            
            if (progress == null) {
                result.put("status", "NOT_FOUND");
                result.put("message", "任务不存在");
                log.debug("任务进度查询: {} - 任务不存在", requestId);
            } else if (progress >= 1.0) {
                result.put("status", "COMPLETED");
                result.put("message", "任务已完成");
                log.info("任务进度查询: {} - 已完成 ({}%)", requestId, progress * 100);
            } else {
                result.put("status", "IN_PROGRESS");
                result.put("message", "任务进行中");
                log.debug("任务进度查询: {} - 进行中 ({}%)", requestId, progress * 100);
            }
            
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            log.error("查询任务进度失败: {}, 错误: {}", requestId, e.getMessage(), e);
            
            Map<String, Object> errorResult = Map.of(
                "requestId", requestId,
                "status", "ERROR",
                "message", "查询进度失败: " + e.getMessage()
            );
            return ResponseEntity.ok(errorResult);
        }
    }

    /**
     * 取消任务
     * 
     * @param requestId 请求ID
     * @return 取消结果
     */
    @PostMapping("/cancel/{requestId}")
    public ResponseEntity<Map<String, Object>> cancelTask(@PathVariable String requestId) {
        log.info("开始取消任务: {}", requestId);
        
        try {
            boolean cancelled = excelReaderService.cancelTask(requestId);
            
            Map<String, Object> result = new HashMap<>();
            result.put("requestId", requestId);
            result.put("success", cancelled);
            
            if (cancelled) {
                result.put("message", "任务已成功取消");
                log.info("任务取消成功: {}", requestId);
            } else {
                result.put("message", "任务取消失败，可能任务不存在或已完成");
                log.warn("任务取消失败: {}, 原因: 任务不存在或已完成", requestId);
            }
            
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            log.error("取消任务异常: {}, 错误: {}", requestId, e.getMessage(), e);
            
            Map<String, Object> errorResult = Map.of(
                "requestId", requestId,
                "success", false,
                "message", "取消任务失败: " + e.getMessage()
            );
            return ResponseEntity.ok(errorResult);
        }
    }

    /**
     * 获取服务状态
     * 
     * @return 服务状态信息
     */
    @GetMapping("/status")
    public ResponseEntity<Map<String, Object>> getServiceStatus() {
        log.debug("开始获取服务状态信息");
        
        try {
            Map<String, Object> status = excelReaderService.getServiceStatus();
            
            log.info("服务状态查询完成: 活跃任务数={}, 线程池状态={}, 内存使用={}MB", 
                    status.get("activeTaskCount"), status.get("threadPoolStatus"), 
                    (Long) status.get("memoryUsage") / 1024 / 1024);
            log.debug("详细服务状态: {}", status);
            
            return ResponseEntity.ok(status);
        } catch (Exception e) {
            log.error("获取服务状态失败: {}", e.getMessage(), e);
            
            Map<String, Object> errorStatus = Map.of(
                "status", "ERROR",
                "message", "获取服务状态失败: " + e.getMessage()
            );
            return ResponseEntity.ok(errorStatus);
        }
    }

    /**
     * 健康检查
     * 
     * @return 健康状态
     */
    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> healthCheck() {
        long startTime = System.currentTimeMillis();
        log.debug("开始健康检查");
        
        try {
            Map<String, Object> health = excelReaderService.healthCheck();
            long responseTime = System.currentTimeMillis() - startTime;
            
            String status = (String) health.get("status");
            if ("UP".equals(status)) {
                log.debug("健康检查通过: 响应时间={}ms", responseTime);
            } else {
                log.warn("健康检查异常: 状态={}, 响应时间={}ms", status, responseTime);
            }
            
            return ResponseEntity.ok(health);
        } catch (Exception e) {
            long responseTime = System.currentTimeMillis() - startTime;
            log.error("健康检查失败: 响应时间={}ms, 错误: {}", responseTime, e.getMessage(), e);
            
            Map<String, Object> errorHealth = Map.of(
                "status", "DOWN",
                "message", "健康检查失败: " + e.getMessage(),
                "timestamp", System.currentTimeMillis()
            );
            return ResponseEntity.ok(errorHealth);
        }
    }
}